using BaseData.Domain;
using BaseData.ErrorCode;
using BaseData.ReadApi.Application.Command;
using BaseData.ReadApi.Dto;
using MediatR;
using Microsoft.Extensions.Logging;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
using AutoMapper;
using BaseData.Infrastructrue.Interfaces;

namespace BaseData.ReadApi.Application.CommandHandler
{
    /// <summary>
    /// 刷新Token命令处理类
    /// </summary>
    public class RefreshTokenCommandHandler : IRequestHandler<RefreshTokenCommand, Apiresult<ResUserOutput>>
    {
        private readonly IBasepository<UserInfo> userpository;
        private readonly IBasepository<Role> rolepository;
        private readonly IBasepository<UserRole> uRpository;
        private readonly IBasepository<Permission> permisspository;
        private readonly IBasepository<RolePermiss> rolePerpository;
        private readonly IMapper mapper;
        private readonly ILogger<RefreshTokenCommandHandler> logger;
        private readonly IConfiguration configuration;  // 配置接口

        /// <summary>
        /// 初始化 <see cref="RefreshTokenCommandHandler"/> 类的新实例。
        /// </summary>
        /// <param name="_userpository">用户信息仓储接口</param>
        /// <param name="_rolepository">角色信息仓储接口</param>
        /// <param name="_URpository">用户角色关联信息仓储接口</param>
        /// <param name="_permisspository">权限信息仓储接口</param>
        /// <param name="_rolePerpository">角色权限关联信息仓储接口</param>
        /// <param name="_mapper">对象映射器</param>
        /// <param name="_logger">日志记录器</param>
        /// <param name="_configuration">配置接口</param>
        public RefreshTokenCommandHandler(
            IBasepository<UserInfo> _userpository,
            IBasepository<Role> _rolepository,
            IBasepository<UserRole> _URpository,
            IBasepository<Permission> _permisspository,
            IBasepository<RolePermiss> _rolePerpository,
            IMapper _mapper,
            ILogger<RefreshTokenCommandHandler> _logger,
            IConfiguration _configuration)
        {
            userpository = _userpository;
            rolepository = _rolepository;
            uRpository = _URpository;
            permisspository = _permisspository;
            rolePerpository = _rolePerpository;
            mapper = _mapper;
            logger = _logger;
            configuration = _configuration;
        }

        public async Task<Apiresult<ResUserOutput>> Handle(RefreshTokenCommand request, CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(request.RefreshToken))
            {
                return CreateErrorResponse("刷新Token不能为空");
            }

            try
            {
                // 验证Refresh Token
                var (isValid, userId) = ValidateRefreshToken(request.RefreshToken);
                if (!isValid || userId <= 0)
                {
                    logger.LogWarning("刷新Token失败：无效的Refresh Token");
                    return CreateErrorResponse("无效的刷新Token");
                }

                // 查找用户信息
                var user = await userpository.GetModel(x => x.UserId == userId);
                if (user == null)
                {
                    logger.LogWarning("刷新Token失败：用户 {UserId} 不存在", userId);
                    return CreateErrorResponse("用户不存在");
                }

                // 创建新的用户结果
                var result = await CreateUserResult(user);
                
                // 生成新的双Token
                var (accessToken, refreshToken, expiryTime) = CreateTokens(result.UserId, result.UserName, result.RoleId, result.RoleName);

                logger.LogInformation("用户 {UserName} 刷新Token成功", result.UserName);

                return new Apiresult<ResUserOutput>
                {
                    Code = ResultCode.查询成功,
                    Message = "Token刷新成功",
                    Result = result,
                    Token = accessToken,
                    RefreshToken = refreshToken,
                    TokenExpiry = expiryTime
                };
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "刷新Token处理出错：错误信息：{ErrorMessage}", ex.Message);
                return CreateErrorResponse("Token刷新处理出错，请稍后再试");
            }
        }

        private (bool isValid, int userId) ValidateRefreshToken(string refreshToken)
        {
            try
            {
                // 从配置中获取JWT设置
                var jwtSettings = configuration.GetSection("Jwt");
                var secretByte = Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]!);
                var signingKey = new SymmetricSecurityKey(secretByte);

                var tokenHandler = new JwtSecurityTokenHandler();
                var validationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = signingKey,
                    ValidateIssuer = true,
                    ValidIssuer = jwtSettings["Issuer"],
                    ValidateAudience = true,
                    ValidAudience = jwtSettings["Audience"],
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };

                // 验证Token
                var principal = tokenHandler.ValidateToken(refreshToken, validationParameters, out var validatedToken);
                
                // 检查Token类型
                var tokenTypeClaim = principal.FindFirst("TokenType")?.Value;
                if (tokenTypeClaim != "refresh")
                {
                    logger.LogWarning("刷新Token验证失败：Token类型错误，期望'refresh'，实际'{TokenType}'", tokenTypeClaim);
                    return (false, 0);
                }

                // 获取用户ID
                var userIdClaim = principal.FindFirst("UserId")?.Value;
                if (string.IsNullOrEmpty(userIdClaim) || !int.TryParse(userIdClaim, out var userId))
                {
                    logger.LogWarning("刷新Token验证失败：用户ID声明无效或缺失，UserIdClaim: '{UserIdClaim}'", userIdClaim);
                    return (false, 0);
                }

                return (true, userId);
            }
            catch (SecurityTokenExpiredException ex)
            {
                logger.LogWarning(ex, "刷新Token验证失败：Token已过期");
                return (false, 0);
            }
            catch (SecurityTokenInvalidSignatureException ex)
            {
                logger.LogWarning(ex, "刷新Token验证失败：Token签名无效");
                return (false, 0);
            }
            catch (SecurityTokenInvalidIssuerException ex)
            {
                logger.LogWarning(ex, "刷新Token验证失败：Token发行者无效或缺失");
                return (false, 0);
            }
            catch (SecurityTokenValidationException ex)
            {
                logger.LogWarning(ex, "刷新Token验证失败：Token验证异常");
                return (false, 0);
            }
            catch (Exception ex)
            {
                logger.LogWarning(ex, "刷新Token验证失败：未知异常");
                return (false, 0);
            }
        }

        private async Task<ResUserOutput> CreateUserResult(UserInfo user)
        {
            var result = mapper.Map<ResUserOutput>(user);

            // 先获取用户角色
            var userRole = await uRpository.GetModel(x => x.UserId == result.UserId);
            if (userRole == null)
            {
                return result; // 如果没有角色信息，直接返回基础用户信息
            }

            // 获取角色信息
            var role = await rolepository.GetModel(x => x.RoleId == userRole.RoleId);
            if (role != null)
            {
                result.RoleId = role.RoleId;
                result.RoleName = role.RoleName ?? "";

                // 获取角色权限关联
                var rolePermiss = await rolePerpository.GetModel(x => x.RoleId == role.RoleId);
                if (rolePermiss != null)
                {
                    // 获取权限信息
                    var permiss = await permisspository.GetModel(x => x.PermissionId == rolePermiss.PermissionId);
                    if (permiss != null)
                    {
                        result.PermissionName = permiss.PermissionName ?? "";
                    }
                }
            }

            return result;
        }

        private (string accessToken, string refreshToken, DateTime expiryTime) CreateTokens(int UserId, string UserName, int RoleId, string RoleName)
        {
            // 从配置中获取JWT设置
            var jwtSettings = configuration.GetSection("Jwt");
            var secretByte = Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]!);
            var signingKey = new SymmetricSecurityKey(secretByte);
            var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);

            var claims = new Claim[]
            {
                new Claim("UserId", UserId.ToString()),
                new Claim("UserName", UserName),
                new Claim("RoleId", RoleId.ToString()),
                new Claim("RoleName", RoleName)
            };

            // 生成Access Token（短期有效）
            var accessTokenExpiry = DateTime.Now.AddMinutes(int.Parse(jwtSettings["AccessTokenExpiryMinutes"]!));
            var accessToken = new JwtSecurityToken(
                issuer: jwtSettings["Issuer"],
                audience: jwtSettings["Audience"],
                expires: accessTokenExpiry,
                signingCredentials: signingCredentials,
                claims: claims
            );

            // 生成Refresh Token（长期有效）
            var refreshTokenExpiry = DateTime.Now.AddDays(int.Parse(jwtSettings["RefreshTokenExpiryDays"]!));
            var refreshToken = new JwtSecurityToken(
                issuer: jwtSettings["Issuer"],
                audience: jwtSettings["Audience"],
                expires: refreshTokenExpiry,
                signingCredentials: signingCredentials,
                claims: new Claim[]
                {
                    new Claim("UserId", UserId.ToString()),
                    new Claim("TokenType", "refresh")
                }
            );

            var jwtHandler = new JwtSecurityTokenHandler();
            return (
                jwtHandler.WriteToken(accessToken),
                jwtHandler.WriteToken(refreshToken),
                accessTokenExpiry
            );
        }

        private Apiresult<ResUserOutput> CreateErrorResponse(string message)
        {
            return new Apiresult<ResUserOutput>
            {
                Code = ResultCode.查询失败,
                Message = message
            };
        }
    }
}